package spindles.api.services;

import java.util.Set;
import java.util.SortedSet;

import spindles.api.db.DAO;
import spindles.api.db.DB;
import spindles.api.db.DBGateway;
import spindles.api.db.PersonDAO;
import spindles.api.domain.Epoch;
import spindles.api.domain.Interval;
import spindles.api.domain.Person;
import spindles.api.domain.SamplingRate;
import spindles.api.domain.SessionPart;
import spindles.api.domain.Settings;
import spindles.api.domain.ThresholdGroup;
import spindles.api.util.ApplicationException;
import spindles.api.util.UserException;

import com.sleepycat.je.Transaction;

public class SettingsService {
	private DBGateway db = new DBGateway(); 
	private PersonDAO personDAO = new PersonDAO();
	private DAO<Epoch> epochDAO = new DAO<Epoch>(Epoch.class, "sessionPartID");
	private DAO<Settings> settingsDAO = new DAO<Settings>(Settings.class);
	
	private Interval softLastISI = null;
	private Interval hardLastISI = null;
	
	public SettingsService(){}
	
	public void saveSettings(Settings s) throws UserException{
		Transaction txn = DB.beginTransaction();
		settingsDAO.setTransaction(txn);
		try {
			settingsDAO.put(s);
			setDefaultThresholdGroup(s.getDefaultGroupName(), txn);			
			DB.commit(txn);
		} catch (ApplicationException e) {
			DB.abort(txn);
			throw e;
		}
	}
	
	public void setDefaultThresholdGroup(String groupName, Transaction txn) {

		DAO<ThresholdGroup> dao = new DAO<ThresholdGroup>(ThresholdGroup.class);
		dao.setTransaction(txn);

		Set<ThresholdGroup> all = dao.findAll();

		for (ThresholdGroup group : all) {

			if (group.getGroupName().equals(groupName)) {
				group.setDefaultGroup(true);
			} else {
				group.setDefaultGroup(false);
			}

			dao.put(group);
		}

	}
	
	public Settings getSettings(){
		return settingsDAO.findAllSorted().first();
	}
	
	public void detectSpindleIndications(String groupName) throws UserException{
		detectSpindleIndications(db.getThresholdGroup(groupName));
	}
	
	private void initISI(){
		softLastISI = null;
		hardLastISI = null;
	}
	
	public void detectSpindleIndications(final ThresholdGroup group) throws UserException{
		final Transaction txn = DB.beginTransaction();
		try {
			personDAO.setTransaction(txn);
			epochDAO.setTransaction(txn);
			
			executeForEachEpoch(new EpochCommand() {
				public void execute(Epoch epoch, SamplingRate samplingRate) {
					if (!epoch.isUsed(group)) {
						epoch.detectAndLoadSpindleIndications(samplingRate,
								group);

						softLastISI = epoch.setISIs(group, true, softLastISI);
						hardLastISI = epoch.setISIs(group, false, hardLastISI);
						epochDAO.put(epoch);
					}
				}
			});

			DB.commit(txn);
		} catch (ApplicationException e) {
			DB.abort(txn);
			throw e;
		}
	}
	
	public void executeForEachEpoch(EpochCommand ec)
			throws UserException {
		Set<Person> persons = personDAO.findAll();
		for (Person person : persons) {
			SortedSet<SessionPart> parts = db.findAllSorted(person.getId());
			for (SessionPart part : parts) {
				initISI();				
				SortedSet<Epoch> epochs = epochDAO.findAllSorted(part.getId());
				for (Epoch epoch : epochs) {
					SamplingRate sr = SamplingRate.toEnum(db
							.getSamplingRate(part.getId()));
					ec.execute(epoch, sr);
				}
			}
		}
	}

}
